home *** CD-ROM | disk | FTP | other *** search
/ AI Game Programming Wisdom / AIGameProgrammingWisdom.iso / SourceCode / 07 DecisionMaking Architectures / 01 Isla, Blumberg / Agent.java < prev    next >
Encoding:
Java Source  |  2001-09-24  |  9.7 KB  |  277 lines

  1. package bb;
  2.  
  3. import java.awt.*;
  4. import java.util.*;
  5. import javax.swing.*;
  6. import java.awt.geom.*;
  7.  
  8. /*
  9. This is the base class for all agents in the BBWar system. All decision-making 
  10. mechanisms are here. Sub classes have mostly to fill in their "SKILLS" hashtable, 
  11. which contains all the abilities that the agent possesses.
  12. */
  13.  
  14. public abstract class Agent extends DrawableObject {
  15.  
  16.     int team;                       //the team we are on.
  17.     World world = null;             //ref to the world.
  18.     Blackboard bb = null;           //ref to the blackboard
  19.     
  20.     Mission currentMission = null;  //the mission we are currently satisfying...
  21.     Skill currentSkill = null;      //the currently-active skill
  22.  
  23.     int rank = 1;                   //military rank
  24.     double maxSpeed = 1.0;          //1.0, let's say, is average...
  25.     double hitPoints = 10.0;        //10.0, let's say, is average...
  26.     double viewRange = 200.0;       //200.0, let's say, is average...
  27.     
  28.     //Note that each agent subclass should have a list of string constants (skills) which
  29.     //indicate the type of mission it can satisfy...
  30.     public Hashtable skills = new Hashtable();
  31.     
  32.     public Agent(int team, int rank, Vec2 pos, double maxSpeed, double hitPoints, Blackboard bb, World world) {
  33.         this(team, rank, pos, maxSpeed, hitPoints, 50.0, bb, world);
  34.     }
  35.     
  36.     public Agent(int team, int rank, Vec2 pos, double maxSpeed, double hitPoints, double viewRange, Blackboard bb, World world) {
  37.         super(pos);
  38.         this.team = team;
  39.         this.rank = rank;
  40.         this.bb = bb;
  41.         this.world = world;
  42.         this.maxSpeed = maxSpeed;
  43.         this.hitPoints = hitPoints;
  44.         this.viewRange = viewRange;
  45.     }
  46.  
  47.     //-----------------------------------ACCESSORS--------------------------------
  48.     
  49.     public int getRank() {
  50.         return rank;   
  51.     }
  52.     
  53.     public int getTeam() {
  54.         return team;
  55.     }
  56.     
  57.     /*----------------------------------ACTION SELECTION-------------------------------
  58.     This is a three-part process - 
  59.     1) In actionSelect() the agent decides which mission it would like to apply for, and
  60.         passes its application along to the blackboard.
  61.     2) The blackboard distributes the missions in its updateMissionAssignments method. In
  62.         the course of this process, it will call back successful applicants with
  63.         grantRequest().
  64.     3) If the mission that was applied for is granted, the agent switches over to that 
  65.         mission (perhaps by removing itself from the current mission, if it has one).
  66.     */
  67.     
  68.     Mission missionPending = null;                  //the mission we've applied for
  69.     public final static double BIAS = 1.1;          //a bias towards staying with the current mission
  70.  
  71.     public void actionSelect(double time) {
  72.         
  73.         Mission highestPriorityMission = null;
  74.         double highestPriority = 0;
  75.  
  76.         //Find the highest-priority relevant mission on the blackboard.
  77.         Iterator iterator = skills.values().iterator();        
  78.         while(iterator.hasNext()) {
  79.             Skill skill = (Skill)iterator.next();
  80.             Vector relevantMissions = bb.getMissionsForSkill(skill);
  81.             for (int d=0; d < relevantMissions.size(); d++) {
  82.                 Mission mission = (Mission)relevantMissions.elementAt(d);
  83.                 double temp = calcPriority(mission, skill);
  84.                 if (temp > highestPriority) {
  85.                     highestPriority = temp;
  86.                     highestPriorityMission = mission;
  87.                 }
  88.             }
  89.         }
  90.  
  91.         //Decide whether we should end our current mission.
  92.         if (currentMission !=null && (currentMission.getMissionComplete() || currentMission.getPriority()==0.0)) {
  93.             System.out.println(this + ": Mission null or complete");
  94.             bb.removeFromMission(this, currentMission);
  95.             currentMission = null;
  96.             if (currentSkill!=null) {
  97.                 currentSkill.deActivate();
  98.                 currentSkill = null;
  99.             }
  100.         }
  101.  
  102.         //Decide whether to apply for the new mission.
  103.         //We have a certain BIAS for staying with our old mission.
  104.         double curPriority = calcPriority(currentMission, currentSkill);
  105.         if ((currentMission == null) || (BIAS*curPriority < highestPriority)) {
  106.             if (highestPriorityMission!=null) bb.applyForMission(this, highestPriorityMission, highestPriority);
  107.             missionPending = highestPriorityMission;
  108.         }
  109.         else missionPending = null;
  110.     }
  111.  
  112.     //This method calculates the priority of a mission.   
  113.     Vec2 scratch = new Vec2();
  114.     double calcPriority(Mission mission, Skill skill) {
  115.         //need to factor in distance as well...
  116.         if (mission==null) return 0;
  117.         double p = mission.getPriority()*skill.getProficiency();
  118.         if (mission instanceof LocatableMission) {
  119.             ((LocatableMission)mission).getTargetPosition(scratch);
  120.             p = p / (1.0 + pos.distance(scratch)/10.0);
  121.         }
  122.         return p;
  123.     }
  124.     
  125.     boolean requestGranted = false;
  126.     public void grantRequest() {
  127.         requestGranted = true;
  128.     }
  129.     
  130.     public void denyRequest() {
  131.         requestGranted = false;
  132.     }
  133.     
  134.     public void actionExecute(double time) {
  135.         //we know the action we are executing.
  136.         //we just need a pointer to the world to do it.
  137.         
  138.         if (!isAlive()) return;
  139.         
  140.  
  141.         //First of all, check if we were expecting a response for a request
  142.         //we made.
  143.         if (missionPending!=null) {
  144.             if (requestGranted) {
  145.                 System.out.println("Agent " + this + " granted mission " + missionPending);
  146.                 if (currentMission != null) bb.removeFromMission(this, currentMission);
  147.                 if (currentSkill!=null) currentSkill.deActivate();  //deactivate old skill
  148.                 currentMission = missionPending;
  149.                 currentSkill = (Skill)skills.get(currentMission.getSkillName());
  150.                 currentSkill.activate();                            //activate new skill
  151.             }
  152.             missionPending = null;
  153.         }
  154.         
  155.         //In some cases, we resort to our default skill...
  156.         if (currentSkill==null || currentMission==null) {
  157.             Skill def = defaultSkill();
  158.             if (currentSkill != def) {
  159.                 if (currentSkill!=null) currentSkill.deActivate();
  160.                 currentSkill = def;
  161.                 currentSkill.activate();
  162.             }
  163.         }
  164.  
  165.         //Finally, apply the current skill to the current mission.
  166.         if (currentSkill!=null) currentSkill.apply(time, currentMission);
  167.     }
  168.  
  169.     //Subclasses might have specific default skills.
  170.     Skill defaultSkill = null;
  171.     public Skill defaultSkill() {
  172.         return defaultSkill;
  173.     }
  174.  
  175.     //---------------------------------INTERACTIONS------------------------------
  176.  
  177.     public void getPosition(Agent askingAgent, Vec2 inplace) {
  178.         inplace.set(pos);
  179.     }
  180.  
  181.     public void damage(double damage) {
  182.         hitPoints -= damage;
  183.         if (hitPoints<=0) die();
  184.     }
  185.     
  186.     public void die() {
  187.         //agents can die!
  188.  
  189.         if (currentSkill!=null) currentSkill.deActivate();
  190.         
  191.         //let the blackboard know that we cannot complete the request...
  192.         bb.removeFromMission(this, currentMission);
  193.  
  194.         System.out.println("Agent " + this + " dying!");
  195.         
  196.         //just DIE!
  197.         alive = false;
  198.     }
  199.  
  200.     boolean alive = true;
  201.     public boolean isAlive() {
  202.         return alive;
  203.     }
  204.  
  205.     //-----------------------------------PHYSICS-----------------------------------
  206.  
  207.     /*
  208.     There are not really full physics, just point-mass physics. Each agent is a mass, 
  209.     on which various forces act, for locomotion, for example, or for attack response 
  210.     (agents get thrown backwards if a strong force hits them).
  211.     */
  212.  
  213.     /*
  214.     These are self-generated forces. This force vector will eventually be normalized
  215.     (since the agent can only go so fast).
  216.     */
  217.     public void addForce(Vec2 f) {
  218.         Vec2.add(force, f, force);
  219.     }
  220.  
  221.     /*
  222.     An external force is, for example, a force from an enemy attack, and does not
  223.     get normalized.
  224.     */
  225.     public void addExternalForce(Vec2 f) {
  226.         Vec2.add(externalForce, f, externalForce);
  227.     }
  228.     
  229.     double mass = 1.0;
  230.     double lasttime = -1.0;
  231.     Vec2 vel = new Vec2();
  232.     Vec2 force = new Vec2();
  233.     Vec2 externalForce = new Vec2();
  234.     double drag;
  235.     public double MAX_ACCEL = 1.0;
  236.     public void updatePhysics(double time) {
  237.         if (lasttime == -1.0) {
  238.             lasttime = time;
  239.             return;
  240.         }
  241.         
  242.         double dt = time - lasttime;
  243.         
  244.         //add in forces from avoiding other agents...eventually
  245.         
  246.         force.scale(1.0/mass);
  247.         double fm = force.mag();
  248.         if (fm > MAX_ACCEL) force.scale(MAX_ACCEL/fm);   //accel can be 0 to MAX_ACCEL.
  249.         force.scale(dt);
  250.         
  251.         Vec2.add(force, externalForce, force);
  252.         externalForce.scale(0.0);
  253.  
  254.         drag = (maxSpeed-dt*MAX_ACCEL)/maxSpeed;
  255.         vel.scale(drag);
  256.         
  257.         Vec2.add(force, vel, vel);
  258.         
  259.         force.set(vel);
  260.         force.scale(dt);
  261.         Vec2.add(force, pos, pos);
  262.         
  263.         force.scale(0.0);
  264.         
  265.         lasttime = time; 
  266.     }
  267.  
  268.     //---------------------------------DRAWGRAPHICS---------------------------------------
  269.  
  270.     //Give the skill a chance to draw itself if it wants to.
  271.     public void updateGraphics(double time, Graphics2D g2) {
  272.         super.updateGraphics(time, g2);
  273.         if (currentSkill!=null) currentSkill.drawSkill(time, g2);
  274.     }
  275.  
  276. }
  277.